#pragma once
#include <Windows.h>
#include <wincodec.h>
#include <DWrite.h>
#include <DXGIType.h>
#include <cmath>
#include <vector>
#include <string>
#include <D2D1.h>
#include <d2d1_3.h>
#include <mutex>
#include "nanosvg.h"
#include "AutoFree.h"
#include "Convert.h"
#include "D2dFont.h"

#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "d2d1.lib")
#pragma comment(lib, "Dwrite.lib")
#pragma comment(lib, "dxguid.lib")
#pragma comment(lib, "windowscodecs.lib")
#define MULBRUSH true

class D2DGraphics
{
    enum target_type
    {
        __hwnd,
        __surface,
        __swapchain,
        __wic,
        __bitmap
    };

private:
    std::mutex mtx;
    target_type _Target_Type = __swapchain;
    IWICBitmap *pWICBitmap = NULL;
    int brush_get_index = 0;
    ID2D1RenderTarget *pRenderTarget = nullptr;
    ID2D1SolidColorBrush *Default_Brush = NULL;
#if MULBRUSH
    List<ID2D1SolidColorBrush *> Brushes = List<ID2D1SolidColorBrush *>();
    inline ID2D1SolidColorBrush *GetBrush()
    {
        ID2D1SolidColorBrush *brush = Brushes[brush_get_index++];
        if (brush_get_index >= Brushes.Count)
            brush_get_index = 0;
        return brush;
    }
#else
    inline ID2D1SolidColorBrush *GetBrush()
    {
        return Default_Brush;
    }
#endif
    __forceinline void SetSolidColorBrushColor(ID2D1SolidColorBrush *brush, const struct _D3DCOLORVALUE *a2)
    {
        brush->SetColor(a2);
    }
    ID2D1SolidColorBrush *GetColorBrush(D2D1_COLOR_F &newcolor)
    {
        auto brush = this->GetBrush();
        SetSolidColorBrushColor(brush, &newcolor);
        return brush;
    }
    ID2D1SolidColorBrush *GetColorBrush(COLORREF &newcolor)
    {
        auto brush = this->GetBrush();
        D2D1_COLOR_F _newcolor = {GetRValue(newcolor) / 255.0f, GetGValue(newcolor) / 255.0f, GetBValue(newcolor) / 255.0f, 1.0f};
        SetSolidColorBrushColor(brush, &_newcolor);
        return brush;
    }
    ID2D1SolidColorBrush *GetColorBrush(int r, int g, int b)
    {
        auto brush = this->GetBrush();
        D2D1_COLOR_F _newcolor = {r / 255.0f, g / 255.0f, b / 255.0f, 1.0f};
        SetSolidColorBrushColor(brush, &_newcolor);
        return brush;
    }
    ID2D1SolidColorBrush *GetColorBrush(float r, float g, float b, float a)
    {
        auto brush = this->GetBrush();
        D2D1_COLOR_F _newcolor = {r, g, b, a};
        SetSolidColorBrushColor(brush, &_newcolor);
        return brush;
    }

public:
    float OffsetX = 0.0f;
    float OffsetY = 0.0f;
    float Zoom = 1.0f;
    HWND WindowHandle;
    bool IsInRender = false;
    D2dFont *DefaultFontObject = nullptr;
    List<D2D1_MATRIX_3X2_F> _pushed_transform;

    D2DGraphics(IDXGISurface *dxgiSurface)
    {
        _Target_Type = __surface;
        D2D1_RENDER_TARGET_PROPERTIES rtDesc = D2D1::RenderTargetProperties(
            D2D1_RENDER_TARGET_TYPE_HARDWARE,
            D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED));
        auto err = _D2DFactory->CreateDxgiSurfaceRenderTarget(
            dxgiSurface,
            &rtDesc,
            &pRenderTarget);
        this->DefaultFontObject = new D2dFont(D2dFont::GetFonts()[0], 14);
#if MULBRUSH
        for (int i = 0; i < 0x100; i++)
        {
            ID2D1SolidColorBrush *brush = nullptr;
            pRenderTarget->CreateSolidColorBrush({0, 1, 0, 1.0f}, &brush);
            this->Brushes.Add(brush);
        }
#endif
        _D3DCOLORVALUE color = {0.5f, 0.6f, 0.7f, 1.0f};
        pRenderTarget->CreateSolidColorBrush(color, &this->Default_Brush);
        this->Default_Brush->SetColor(color);
        // this->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);
        // this->SetTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_ALIASED);
    }
    D2DGraphics(IDXGISwapChain *swap_chain_ptr)
    {
        _Target_Type = __swapchain;
        IDXGISurface *pBackBuffer;
        swap_chain_ptr->GetBuffer(
            0,
            IID_PPV_ARGS(&pBackBuffer));
        D2D1_RENDER_TARGET_PROPERTIES rtDesc = D2D1::RenderTargetProperties(
            D2D1_RENDER_TARGET_TYPE_HARDWARE,
            D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED));
        auto err = _D2DFactory->CreateDxgiSurfaceRenderTarget(
            pBackBuffer,
            &rtDesc,
            &pRenderTarget);
        this->DefaultFontObject = new D2dFont(D2dFont::GetFonts()[0], 14);
#if MULBRUSH
        for (int i = 0; i < 0x100; i++)
        {
            ID2D1SolidColorBrush *brush = nullptr;
            pRenderTarget->CreateSolidColorBrush({0, 1, 0, 1.0f}, &brush);
            this->Brushes.Add(brush);
        }
#endif
        _D3DCOLORVALUE color = {0.5f, 0.6f, 0.7f, 1.0f};
        pRenderTarget->CreateSolidColorBrush(color, &this->Default_Brush);
        this->Default_Brush->SetColor(color);
        // this->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);
        // this->SetTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_ALIASED);
    }
    D2DGraphics(HWND hWnd)
    {
        _Target_Type = __hwnd;
        this->WindowHandle = hWnd;
        D2D1_RENDER_TARGET_PROPERTIES rtDesc = D2D1::RenderTargetProperties(
            D2D1_RENDER_TARGET_TYPE_HARDWARE,
            D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED));
        RECT rc = {0, 0, 0, 0};
        GetClientRect(this->WindowHandle, &rc);
        auto err = _D2DFactory->CreateHwndRenderTarget(
            D2D1::RenderTargetProperties(),
            D2D1::HwndRenderTargetProperties(this->WindowHandle, D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top)),
            (ID2D1HwndRenderTarget **)&pRenderTarget);
        this->DefaultFontObject = new D2dFont(D2dFont::GetFonts()[0], 14);
#if MULBRUSH
        for (int i = 0; i < 0x100; i++)
        {
            ID2D1SolidColorBrush *brush = nullptr;
            pRenderTarget->CreateSolidColorBrush({0, 1, 0, 1.0f}, &brush);
            this->Brushes.Add(brush);
        }
#endif
        _D3DCOLORVALUE color = {0.5f, 0.6f, 0.7f, 1.0f};
        pRenderTarget->CreateSolidColorBrush(color, &this->Default_Brush);
        this->Default_Brush->SetColor(color);
    }
    D2DGraphics(int width, int height)
    {
        _Target_Type = __wic;
        auto st = _ImageFactory->CreateBitmap(
            width,
            height,
            GUID_WICPixelFormat32bppBGR,
            WICBitmapCacheOnLoad,
            &pWICBitmap);
        st = _D2DFactory->CreateWicBitmapRenderTarget(
            pWICBitmap,
            D2D1::RenderTargetProperties(),
            &pRenderTarget);
        this->DefaultFontObject = new D2dFont(D2dFont::GetFonts()[0], 14);
#if MULBRUSH
        for (int i = 0; i < 0x100; i++)
        {
            ID2D1SolidColorBrush *brush = nullptr;
            pRenderTarget->CreateSolidColorBrush({0, 1, 0, 1.0f}, &brush);
            this->Brushes.Add(brush);
        }
#endif
        _D3DCOLORVALUE color = {0.5f, 0.6f, 0.7f, 1.0f};
        pRenderTarget->CreateSolidColorBrush(color, &this->Default_Brush);
        this->Default_Brush->SetColor(color);
        // this->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);
        // this->SetTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_ALIASED);
    }
    D2DGraphics(IWICBitmap *wic)
    {
        UINT w, h;
        wic->GetSize(&w, &h);
        _Target_Type = __wic;
        auto st = _ImageFactory->CreateBitmap(
            w,
            h,
            GUID_WICPixelFormat32bppBGR,
            WICBitmapCacheOnLoad,
            &pWICBitmap);
        st = _D2DFactory->CreateWicBitmapRenderTarget(
            pWICBitmap,
            D2D1::RenderTargetProperties(),
            &pRenderTarget);
        this->DefaultFontObject = new D2dFont(D2dFont::GetFonts()[0], 14);
#if MULBRUSH
        for (int i = 0; i < 0x100; i++)
        {
            ID2D1SolidColorBrush *brush = nullptr;
            pRenderTarget->CreateSolidColorBrush({0, 1, 0, 1.0f}, &brush);
            this->Brushes.Add(brush);
        }
#endif
        _D3DCOLORVALUE color = {0.5f, 0.6f, 0.7f, 1.0f};
        pRenderTarget->CreateSolidColorBrush(color, &this->Default_Brush);
        this->Default_Brush->SetColor(color);
        auto bbmp = this->CreateBitmap(wic);
        this->BeginRender();
        this->DrawBitmap(bbmp, 0, 0, w, h);
        this->EndRender();
        // this->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);
        // this->SetTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_ALIASED);
    }
    D2DGraphics(ID2D1Bitmap *bmp)
    {
        auto size = bmp->GetSize();
        _Target_Type = __wic;
        auto st = _ImageFactory->CreateBitmap(
            (UINT)size.width,
            (UINT)size.height,
            GUID_WICPixelFormat32bppBGR,
            WICBitmapCacheOnLoad,
            &pWICBitmap);
        st = _D2DFactory->CreateWicBitmapRenderTarget(
            pWICBitmap,
            D2D1::RenderTargetProperties(),
            &pRenderTarget);
        this->DefaultFontObject = new D2dFont(D2dFont::GetFonts()[0], 14);
#if MULBRUSH
        for (int i = 0; i < 0x100; i++)
        {
            ID2D1SolidColorBrush *brush = nullptr;
            pRenderTarget->CreateSolidColorBrush({0, 1, 0, 1.0f}, &brush);
            this->Brushes.Add(brush);
        }
#endif
        _D3DCOLORVALUE color = {0.5f, 0.6f, 0.7f, 1.0f};
        pRenderTarget->CreateSolidColorBrush(color, &this->Default_Brush);
        this->Default_Brush->SetColor(color);
        this->BeginRender();
        this->DrawBitmap(bmp, 0, 0, size.width, size.height);
        this->EndRender();
        // this->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);
        // this->SetTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_ALIASED);
    }
    D2DGraphics(ID2D1BitmapRenderTarget *target)
    {
        _Target_Type = __bitmap;
        pRenderTarget = target;
        this->DefaultFontObject = new D2dFont(D2dFont::GetFonts()[0], 14);
#if MULBRUSH
        for (int i = 0; i < 0x100; i++)
        {
            ID2D1SolidColorBrush *brush = nullptr;
            pRenderTarget->CreateSolidColorBrush({0, 1, 0, 1.0f}, &brush);
            this->Brushes.Add(brush);
        }
#endif
        _D3DCOLORVALUE color = {0.5f, 0.6f, 0.7f, 1.0f};
        pRenderTarget->CreateSolidColorBrush(color, &this->Default_Brush);
        this->Default_Brush->SetColor(color);
        // this->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);
        // this->SetTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_ALIASED);
    }
    ~D2DGraphics()
    {
        delete DefaultFontObject;
        DefaultFontObject = NULL;
    }
    static inline D2D1_MATRIX_3X2_F MakeTransform(float show_percentage, float x_offset, float y_offset)
    {
        D2D1_MATRIX_3X2_F translation = D2D1::Matrix3x2F::Translation(x_offset, y_offset);
        D2D1_MATRIX_3X2_F translation1 = D2D1::Matrix3x2F::Scale(
            D2D1::Size(show_percentage, show_percentage),
            D2D1::Point2F(0, 0));
        return translation1 * translation;
    }

    ID2D1LinearGradientBrush *CreateLinearGradientBrush(D2D1_GRADIENT_STOP *stops, unsigned int stopcount)
    {
        ID2D1GradientStopCollection *collection;
        if SUCCEEDED (pRenderTarget->CreateGradientStopCollection(stops, stopcount, &collection))
        {
            D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES props = {};
            ID2D1LinearGradientBrush *m_LinearBrush;
            if SUCCEEDED (pRenderTarget->CreateLinearGradientBrush(props, collection, &m_LinearBrush))
            {
                collection->Release();
                return m_LinearBrush;
            }
            collection->Release();
        }
        return NULL;
    }
    ID2D1RadialGradientBrush *CreateRadialGradientBrush(D2D1_GRADIENT_STOP *stops, unsigned int stopcount, D2D1_POINT_2F center)
    {
        ID2D1GradientStopCollection *collection;
        if SUCCEEDED (pRenderTarget->CreateGradientStopCollection(stops, stopcount, &collection))
        {
            D2D1_RADIAL_GRADIENT_BRUSH_PROPERTIES props = {};
            props.center = center;
            ID2D1RadialGradientBrush *brush;
            if SUCCEEDED (pRenderTarget->CreateRadialGradientBrush(props, collection, &brush))
            {
                collection->Release();
                return brush;
            }
            collection->Release();
        }
        return NULL;
    }
    void SetTransform(float zoom, float xf, float yf)
    {
        OffsetX = xf;
        OffsetY = yf;
        Zoom = zoom;
        this->pRenderTarget->SetTransform(MakeTransform(Zoom, OffsetX, OffsetY));
    }
    void PushTransform(float zoom, float xf, float yf)
    {
        D2D1_MATRIX_3X2_F last = {};
        this->pRenderTarget->GetTransform(&last);
        OffsetX = xf;
        OffsetY = yf;
        Zoom = zoom;
        auto tr = MakeTransform(Zoom, OffsetX, OffsetY);
        this->pRenderTarget->SetTransform(tr);
        _pushed_transform.Add(last);
    }
    void PopTransform()
    {
        if (_pushed_transform.Count > 0)
        {
            auto tr = _pushed_transform[_pushed_transform.Count - 1];
            this->pRenderTarget->SetTransform(tr);
            _pushed_transform.RemoveAt(_pushed_transform.Count - 1);
        }
    }
    D2DGraphics *CreateSubGraphics(int width, int height)
    {
        ID2D1BitmapRenderTarget *target = NULL;
        this->pRenderTarget->CreateCompatibleRenderTarget(D2D1_SIZE_F{(float)width, (float)height}, &target);
        return new D2DGraphics(target);
    }
    D2D1_SIZE_F Size()
    {
        return this->pRenderTarget->GetSize();
    }
    void Resize()
    {
        if (this->WindowHandle)
        {
            RECT rc = {0, 0, 0, 0};
            GetClientRect(this->WindowHandle, &rc);
            ((ID2D1HwndRenderTarget *)this->pRenderTarget)->Resize(D2D1_SIZE_U{(UINT32)rc.right - (UINT32)rc.left, (UINT32)rc.bottom - (UINT32)rc.top});
        }
    }
    void ResizeSubGraphics(int width, int height)
    {
        DefaultFontObject->~D2dFont();
        this->pRenderTarget->Release();
        ID2D1BitmapRenderTarget *target = NULL;
        this->pRenderTarget->CreateCompatibleRenderTarget(D2D1_SIZE_F{(float)width, (float)height}, &target);
        _Target_Type = __bitmap;
        pRenderTarget = target;
        this->DefaultFontObject = new D2dFont(D2dFont::GetFonts()[0], 14);
        _D3DCOLORVALUE color = {0.5f, 0.6f, 0.7f, 1.0f};
        pRenderTarget->CreateSolidColorBrush(color, &this->Default_Brush);
        this->Default_Brush->SetColor(color);
    }
    void BeginRender(CONST D2D1_COLOR_F clearColor)
    {
        mtx.lock();
        if (IsInRender == false)
        {
            pRenderTarget->BeginDraw();
            IsInRender = true;
            this->pRenderTarget->Clear(clearColor);
        }
        mtx.unlock();
    }
    void BeginRender()
    {
        mtx.lock();
        if (IsInRender == false)
        {
            pRenderTarget->BeginDraw();
            IsInRender = true;
        }
        mtx.unlock();
    }
    void EndRender()
    {
        mtx.lock();
        if (IsInRender)
        {
            pRenderTarget->EndDraw();
            IsInRender = false;
        }
        mtx.unlock();
    }
    void DrawLine(D2D1_POINT_2F p1, D2D1_POINT_2F p2, D2D1_COLOR_F color, float linewidth = 1.0f)
    {
        this->pRenderTarget->DrawLine(p1, p2, this->GetColorBrush(color), linewidth);
    }
    void DrawLine(float p1_x, float p1_y, float p2_x, float p2_y, D2D1_COLOR_F color, float linewidth = 1.0f)
    {
        this->pRenderTarget->DrawLine({p1_x, p1_y}, {p2_x, p2_y}, this->GetColorBrush(color), linewidth);
    }
    void DrawLine(D2D1_POINT_2F p1, D2D1_POINT_2F p2, ID2D1Brush *brush, float linewidth = 1.0f)
    {
        this->pRenderTarget->DrawLine(p1, p2, brush, linewidth);
    }
    void DrawLine(float p1_x, float p1_y, float p2_x, float p2_y, ID2D1Brush *brush, float linewidth = 1.0f)
    {
        this->pRenderTarget->DrawLine({p1_x, p1_y}, {p2_x, p2_y}, brush, linewidth);
    }
    void DrawRect(float left, float top, float width, float height, D2D1_COLOR_F color, float linewidth = 1.0f)
    {
        this->pRenderTarget->DrawRectangle({left, top, left + width, top + height}, this->GetColorBrush(color), linewidth);
    }
    void DrawRoundRect(float left, float top, float width, float height, D2D1_COLOR_F color, float linewidth = 1.0f, float r = 0.5f)
    {
        D2D1_ROUNDED_RECT round = D2D1::RoundedRect(
            D2D1::RectF(left, top, left + width, top + height),
            r,
            r);
        this->pRenderTarget->DrawRoundedRectangle(round, this->GetColorBrush(color), linewidth);
    }
    void FillRect(float left, float top, float width, float height, D2D1_COLOR_F color)
    {
        this->pRenderTarget->FillRectangle({left, top, left + width, top + height}, this->GetColorBrush(color));
    }
    void FillRoundRect(float left, float top, float width, float height, D2D1_COLOR_F color, float r = 0.5f)
    {
        D2D1_ROUNDED_RECT round = D2D1::RoundedRect(
            D2D1::RectF(left, top, left + width, top + height),
            r,
            r);
        this->pRenderTarget->FillRoundedRectangle(round, this->GetColorBrush(color));
    }
    void DrawEllipse(D2D1_POINT_2F cent, float xr, float yr, D2D1_COLOR_F color, float linewidth = 1.0f)
    {
        this->pRenderTarget->DrawEllipse({cent, xr, yr}, this->GetColorBrush(color), linewidth = 1.0f);
    }
    void DrawEllipse(D2D1_ELLIPSE ellipse, D2D1_COLOR_F color, float linewidth = 1.0f)
    {
        this->pRenderTarget->DrawEllipse(ellipse, this->GetColorBrush(color), linewidth);
    }
    void DrawEllipse(float x, float y, float xr, float yr, D2D1_COLOR_F color, float linewidth = 1.0f)
    {
        this->pRenderTarget->DrawEllipse({{x, y}, xr, yr}, this->GetColorBrush(color), linewidth = 1.0f);
    }
    void FillEllipse(D2D1_ELLIPSE ellipse, D2D1_COLOR_F color)
    {
        this->pRenderTarget->FillEllipse(ellipse, this->GetColorBrush(color));
    }
    void FillEllipse(D2D1_POINT_2F cent, float xr, float yr, D2D1_COLOR_F color)
    {
        this->pRenderTarget->FillEllipse({cent, xr, yr}, this->GetColorBrush(color));
    }
    void FillEllipse(float cx, float cy, float xr, float yr, D2D1_COLOR_F color)
    {
        this->pRenderTarget->FillEllipse({{cx, cy}, xr, yr}, this->GetColorBrush(color));
    }
    void DrawGeometry(ID2D1Geometry *geo, D2D1_COLOR_F color, float linewidth)
    {
        this->pRenderTarget->DrawGeometry(geo, this->GetColorBrush(color), linewidth);
    }
    void FillGeometry(ID2D1Geometry *geo, D2D1_COLOR_F color)
    {
        this->pRenderTarget->FillGeometry(geo, this->GetColorBrush(color));
    }
    void DrawGeometry(ID2D1Geometry *geo, ID2D1Brush *brush, float linewidth)
    {
        this->pRenderTarget->DrawGeometry(geo, brush, linewidth);
    }
    void FillGeometry(ID2D1Geometry *geo, ID2D1Brush *brush)
    {
        this->pRenderTarget->FillGeometry(geo, brush);
    }
    void FillMesh(ID2D1Mesh *mesh, D2D1_COLOR_F color)
    {
        this->pRenderTarget->FillMesh(mesh, this->GetColorBrush(color));
    }
    void DrawBitmap(ID2D1Bitmap *bmp, float x, float y, float opacity = 1.0f, D2D1_COLOR_F border = {0, 0, 0, 0}, float borderwidth = 1.0f)
    {
        if (this->pRenderTarget && bmp)
        {
            this->pRenderTarget->DrawBitmap(
                bmp,
                {x, y,
                 bmp->GetSize().width + x,
                 bmp->GetSize().height + y},
                opacity, D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR);
        }
    }
    void DrawBitmap(ID2D1Bitmap *bmp, float x, float y, float w, float h, float opacity = 1.0f, D2D1_COLOR_F border = {0, 0, 0, 0}, float borderwidth = 1.0f)
    {
        if (this->pRenderTarget && bmp)
        {
            this->pRenderTarget->DrawBitmap(
                bmp,
                {x, y,
                 w == 0 ? bmp->GetSize().width + x : w + x,
                 h == 0 ? bmp->GetSize().height + y : h + y},
                opacity, D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR);
            if (border.a > 0.0f)
            {
                this->DrawRect(x, y, w, h, border, borderwidth);
            }
        }
    }
    void DrawBitmap(ID2D1Bitmap *bmp,
                    float sx, float sy, float sw, float sh,
                    float x, float y, float w, float h,
                    float opacity = 1.0f,
                    D2D1_COLOR_F border = {0, 0, 0, 0},
                    float borderwidth = 1.0f)
    {
        if (this->pRenderTarget && bmp)
        {
            D2D1_RECT_F srec = {
                sx, sy,
                sw + sx,
                sh + sy};
            D2D1_RECT_F drec = {
                x, y,
                w == 0 ? bmp->GetSize().width + x : w + x,
                h == 0 ? bmp->GetSize().height + y : h + y};
            this->pRenderTarget->DrawBitmap(
                bmp,
                drec,
                opacity,
                D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR,
                srec);

            if (border.a > 0.0f)
            {
                this->DrawRect(x, y, w, h, border, borderwidth);
            }
        }
    }
    void DrawString(const char *str, float x, float y, ID2D1Brush *brush, D2dFont *font = nullptr)
    {
        AutoFree<wchar_t> tmp = Convert::A2W(str);

        this->pRenderTarget->DrawTextW(
            tmp,
            wcslen(tmp),
            font ? font->_d2d_obj : this->DefaultFontObject->_d2d_obj,
            D2D1::RectF(x, y, x + 10000.0f, y + 10000.0f),
            brush);
    }
    void DrawString(const wchar_t *str, float x, float y, ID2D1Brush *brush, D2dFont *font = nullptr)
    {
        this->pRenderTarget->DrawTextW(
            str,
            wcslen(str),
            font ? font->_d2d_obj : this->DefaultFontObject->_d2d_obj,
            D2D1::RectF(x, y, x + 10000.0f, y + 10000.0f),
            brush);
    }
    void DrawString(const char *str, float x, float y, D2D1_COLOR_F color, D2dFont *font = nullptr)
    {
        AutoFree<wchar_t> tmp = Convert::A2W(str);
        this->pRenderTarget->DrawTextW(
            tmp,
            wcslen(tmp),
            font ? font->_d2d_obj : this->DefaultFontObject->_d2d_obj,
            D2D1::RectF(x, y, x + 10000.0f, y + 10000.0f),
            this->GetColorBrush(color));
    }
    void DrawString(const wchar_t *str, float x, float y, D2D1_COLOR_F color, D2dFont *font = nullptr)
    {
        this->pRenderTarget->DrawTextW(
            str,
            wcslen(str),
            font ? font->_d2d_obj : this->DefaultFontObject->_d2d_obj,
            D2D1::RectF(x, y, x + 10000.0f, y + 10000.0f),
            this->GetColorBrush(color));
    }
    void DrawString(std::string str, float x, float y, D2D1_COLOR_F color, D2dFont *font = nullptr)
    {
        AutoFree<wchar_t> tmp = Convert::A2W(str);
        this->pRenderTarget->DrawTextW(
            tmp,
            wcslen(tmp),
            font ? font->_d2d_obj : this->DefaultFontObject->_d2d_obj,
            D2D1::RectF(x, y, x + 10000.0f, y + 10000.0f),
            this->GetColorBrush(color));
    }
    void DrawString(std::string str, float x, float y, ID2D1Brush *brush, D2dFont *font = nullptr)
    {
        AutoFree<wchar_t> tmp = Convert::A2W(str);
        this->pRenderTarget->DrawTextW(
            tmp,
            wcslen(tmp),
            font ? font->_d2d_obj : this->DefaultFontObject->_d2d_obj,
            D2D1::RectF(x, y, x + 10000.0f, y + 10000.0f),
            brush);
    }
    void DrawString(std::wstring str, float x, float y, D2D1_COLOR_F color, D2dFont *font = nullptr)
    {
        this->pRenderTarget->DrawTextW(
            str.c_str(),
            str.size(),
            font ? font->_d2d_obj : this->DefaultFontObject->_d2d_obj,
            D2D1::RectF(x, y, x + 10000.0f, y + 10000.0f),
            this->GetColorBrush(color));
    }
    void DrawString(std::wstring str, float x, float y, ID2D1Brush *brush, D2dFont *font = nullptr)
    {
        this->pRenderTarget->DrawTextW(
            str.c_str(),
            str.size(),
            font ? font->_d2d_obj : this->DefaultFontObject->_d2d_obj,
            D2D1::RectF(x, y, x + 10000.0f, y + 10000.0f),
            brush);
    }
    IDWriteTextLayout *CreateStringLayout(std::string str, D2dFont *font = nullptr)
    {
        IDWriteTextLayout *textLayout = 0;
        AutoFree<wchar_t> tmp = Convert::A2W(str);
        HRESULT hr = _DWriteFactory->CreateTextLayout(
            tmp,
            wcslen(tmp),
            font ? font->_d2d_obj : this->DefaultFontObject->_d2d_obj,
            10000000,
            10000000,
            &textLayout);
        return textLayout;
    }
    IDWriteTextLayout *CreateStringLayout(std::wstring str, D2dFont *font = nullptr)
    {
        IDWriteTextLayout *textLayout = 0;
        HRESULT hr = _DWriteFactory->CreateTextLayout(
            str.c_str(),
            str.size(),
            font ? font->_d2d_obj : this->DefaultFontObject->_d2d_obj,
            10000000,
            10000000,
            &textLayout);
        return textLayout;
    }
    IDWriteTextLayout *CreateStringLayout(std::wstring str, float width, float height, D2dFont *font = nullptr)
    {
        IDWriteTextLayout *textLayout = 0;
        HRESULT hr = _DWriteFactory->CreateTextLayout(
            str.c_str(),
            str.size(),
            font ? font->_d2d_obj : this->DefaultFontObject->_d2d_obj,
            width,
            height,
            &textLayout);
        return textLayout;
    }
    void DrawStringLayout(IDWriteTextLayout *layout, float x, float y, D2D1_COLOR_F color)
    {
        this->pRenderTarget->DrawTextLayout(
            {x, y},
            layout,
            this->GetColorBrush(color));
    }
    void DrawStringLayout(IDWriteTextLayout *layout, float x, float y, ID2D1Brush *brush)
    {
        this->pRenderTarget->DrawTextLayout(
            {x, y},
            layout,
            brush);
    }
    D2D1_SIZE_F DrawStringLayoutCent(IDWriteTextLayout *layout, float x, float y, D2D1_COLOR_F color, D2D1_COLOR_F back = {0.0f, 0.0f, 0.0f, 0.0f})
    {
        DWRITE_TEXT_METRICS metrics;
        auto hr = layout->GetMetrics(&metrics);
        auto tsize = D2D1::Size((float)ceil(metrics.widthIncludingTrailingWhitespace), (float)ceil(metrics.height));

        D2D1_POINT_2F loc = {x - (tsize.width / 2.0f), y - (tsize.height / 2.0f)};
        if (back.a > 0.0f)
        {
            auto brush = this->GetColorBrush(back);
            this->pRenderTarget->DrawTextLayout({loc.x - 1, loc.y - 1}, layout, brush);
            this->pRenderTarget->DrawTextLayout({loc.x + 1, loc.y + 1}, layout, brush);
            this->pRenderTarget->DrawTextLayout({loc.x - 1, loc.y + 1}, layout, brush);
            this->pRenderTarget->DrawTextLayout({loc.x + 1, loc.y - 1}, layout, brush);
        }
        this->pRenderTarget->DrawTextLayout({loc.x, loc.y}, layout, this->GetColorBrush(color));
        return tsize;
    }
    D2D1_SIZE_F DrawStringCent(std::string str, float x, float y, D2D1_COLOR_F color, IDWriteTextLayout **_recodeLayout = nullptr, D2D1_COLOR_F back = {0.0f, 0.0f, 0.0f, 0.0f}, D2dFont *font = nullptr)
    {
        D2D1_SIZE_F tsize = {0, 0};
        AutoFree<wchar_t> tmp = Convert::A2W(str);
        IDWriteTextLayout *textLayout = CreateStringLayout(str, font ? font : this->DefaultFontObject);
        if (textLayout)
        {
            DWRITE_TEXT_METRICS metrics;
            auto hr = textLayout->GetMetrics(&metrics);
            if (SUCCEEDED(hr))
            {
                tsize = D2D1::Size((float)ceil(metrics.widthIncludingTrailingWhitespace), (float)ceil(metrics.height));
                D2D1_POINT_2F loc = {x - (tsize.width / 2.0f), y - (tsize.height / 2.0f)};
                if (back.a > 0.0f)
                {
                    auto brush = this->GetColorBrush(back);
                    this->pRenderTarget->DrawTextLayout({loc.x - 1, loc.y - 1}, textLayout, brush);
                    this->pRenderTarget->DrawTextLayout({loc.x + 1, loc.y + 1}, textLayout, brush);
                    this->pRenderTarget->DrawTextLayout({loc.x - 1, loc.y + 1}, textLayout, brush);
                    this->pRenderTarget->DrawTextLayout({loc.x + 1, loc.y - 1}, textLayout, brush);
                }
                this->pRenderTarget->DrawTextLayout(
                    loc,
                    textLayout,
                    this->GetColorBrush(color));
            }
            if (_recodeLayout)
                *_recodeLayout = textLayout;
            else
                textLayout->Release();
        }
        return tsize;
    }
    D2D1_SIZE_F DrawStringCent(std::wstring str, float x, float y, D2D1_COLOR_F color, IDWriteTextLayout **_recodeLayout = nullptr, D2D1_COLOR_F back = {0.0f, 0.0f, 0.0f, 0.0f}, D2dFont *font = nullptr)
    {
        D2D1_SIZE_F tsize = {0, 0};
        IDWriteTextLayout *textLayout = CreateStringLayout(str, font ? font : this->DefaultFontObject);
        if (textLayout)
        {
            DWRITE_TEXT_METRICS metrics;
            auto hr = textLayout->GetMetrics(&metrics);
            if (SUCCEEDED(hr))
            {
                tsize = D2D1::Size((float)ceil(metrics.widthIncludingTrailingWhitespace), (float)ceil(metrics.height));
                D2D1_POINT_2F loc = {x - (tsize.width / 2.0f), y - (tsize.height / 2.0f)};
                if (back.a > 0.0f)
                {
                    auto brush = this->GetColorBrush(back);
                    this->pRenderTarget->DrawTextLayout({loc.x - 1, loc.y - 1}, textLayout, brush);
                    this->pRenderTarget->DrawTextLayout({loc.x + 1, loc.y + 1}, textLayout, brush);
                    this->pRenderTarget->DrawTextLayout({loc.x - 1, loc.y + 1}, textLayout, brush);
                    this->pRenderTarget->DrawTextLayout({loc.x + 1, loc.y - 1}, textLayout, brush);
                }
                this->pRenderTarget->DrawTextLayout(loc, textLayout, this->GetColorBrush(color));
            }
            if (_recodeLayout)
                *_recodeLayout = textLayout;
            else
                textLayout->Release();
        }
        return tsize;
    }
    D2D1_SIZE_F DrawStringLayoutCentHorizontal(IDWriteTextLayout *layout, float x, float y, D2D1_COLOR_F color, D2D1_COLOR_F back = {0.0f, 0.0f, 0.0f, 0.0f})
    {
        DWRITE_TEXT_METRICS metrics;
        auto hr = layout->GetMetrics(&metrics);
        auto tsize = D2D1::Size((float)ceil(metrics.widthIncludingTrailingWhitespace), (float)ceil(metrics.height));

        D2D1_POINT_2F loc = {x - (tsize.width / 2.0f), y};
        if (back.a > 0.0f)
        {
            auto brush = this->GetColorBrush(back);
            this->pRenderTarget->DrawTextLayout({loc.x - 1, loc.y - 1}, layout, brush);
            this->pRenderTarget->DrawTextLayout({loc.x + 1, loc.y + 1}, layout, brush);
            this->pRenderTarget->DrawTextLayout({loc.x - 1, loc.y + 1}, layout, brush);
            this->pRenderTarget->DrawTextLayout({loc.x + 1, loc.y - 1}, layout, brush);
        }
        this->pRenderTarget->DrawTextLayout({loc.x, loc.y}, layout, this->GetColorBrush(color));
        return tsize;
    }
    D2D1_SIZE_F DrawStringCentHorizontal(std::string str, float x, float y, D2D1_COLOR_F color, IDWriteTextLayout **_recodeLayout = nullptr, D2D1_COLOR_F back = {0.0f, 0.0f, 0.0f, 0.0f}, D2dFont *font = nullptr)
    {
        D2D1_SIZE_F tsize = {0, 0};
        AutoFree<wchar_t> tmp = Convert::A2W(str);
        IDWriteTextLayout *textLayout = CreateStringLayout(str, font ? font : this->DefaultFontObject);
        if (textLayout)
        {
            DWRITE_TEXT_METRICS metrics;
            auto hr = textLayout->GetMetrics(&metrics);
            if (SUCCEEDED(hr))
            {
                tsize = D2D1::Size((float)ceil(metrics.widthIncludingTrailingWhitespace), (float)ceil(metrics.height));
                D2D1_POINT_2F loc = {x - (tsize.width / 2.0f), y};
                if (back.a > 0.0f)
                {
                    auto brush = this->GetColorBrush(back);
                    this->pRenderTarget->DrawTextLayout({loc.x - 1, loc.y - 1}, textLayout, brush);
                    this->pRenderTarget->DrawTextLayout({loc.x + 1, loc.y + 1}, textLayout, brush);
                    this->pRenderTarget->DrawTextLayout({loc.x - 1, loc.y + 1}, textLayout, brush);
                    this->pRenderTarget->DrawTextLayout({loc.x + 1, loc.y - 1}, textLayout, brush);
                }
                this->pRenderTarget->DrawTextLayout(
                    loc,
                    textLayout,
                    this->GetColorBrush(color));
            }
            if (_recodeLayout)
                *_recodeLayout = textLayout;
            else
                textLayout->Release();
        }
        return tsize;
    }
    D2D1_SIZE_F DrawStringCentHorizontal(std::wstring str, float x, float y, D2D1_COLOR_F color, IDWriteTextLayout **_recodeLayout = nullptr, D2D1_COLOR_F back = {0.0f, 0.0f, 0.0f, 0.0f}, D2dFont *font = nullptr)
    {
        D2D1_SIZE_F tsize = {0, 0};
        IDWriteTextLayout *textLayout = CreateStringLayout(str, font ? font : this->DefaultFontObject);
        if (textLayout)
        {
            DWRITE_TEXT_METRICS metrics;
            auto hr = textLayout->GetMetrics(&metrics);
            if (SUCCEEDED(hr))
            {
                tsize = D2D1::Size((float)ceil(metrics.widthIncludingTrailingWhitespace), (float)ceil(metrics.height));
                D2D1_POINT_2F loc = {x - (tsize.width / 2.0f), y};
                if (back.a > 0.0f)
                {
                    auto brush = this->GetColorBrush(back);
                    this->pRenderTarget->DrawTextLayout({loc.x - 1, loc.y - 1}, textLayout, brush);
                    this->pRenderTarget->DrawTextLayout({loc.x + 1, loc.y + 1}, textLayout, brush);
                    this->pRenderTarget->DrawTextLayout({loc.x - 1, loc.y + 1}, textLayout, brush);
                    this->pRenderTarget->DrawTextLayout({loc.x + 1, loc.y - 1}, textLayout, brush);
                }
                this->pRenderTarget->DrawTextLayout(loc, textLayout, this->GetColorBrush(color));
            }
            if (_recodeLayout)
                *_recodeLayout = textLayout;
            else
                textLayout->Release();
        }
        return tsize;
    }
    D2D1_SIZE_F DrawStringLayoutCentVertical(IDWriteTextLayout *layout, float x, float y, D2D1_COLOR_F color, D2D1_COLOR_F back = {0.0f, 0.0f, 0.0f, 0.0f})
    {
        DWRITE_TEXT_METRICS metrics;
        auto hr = layout->GetMetrics(&metrics);
        auto tsize = D2D1::Size((float)ceil(metrics.widthIncludingTrailingWhitespace), (float)ceil(metrics.height));

        D2D1_POINT_2F loc = {x, y - (tsize.height / 2.0f)};
        if (back.a > 0.0f)
        {
            auto brush = this->GetColorBrush(back);
            this->pRenderTarget->DrawTextLayout({loc.x - 1, loc.y - 1}, layout, brush);
            this->pRenderTarget->DrawTextLayout({loc.x + 1, loc.y + 1}, layout, brush);
            this->pRenderTarget->DrawTextLayout({loc.x - 1, loc.y + 1}, layout, brush);
            this->pRenderTarget->DrawTextLayout({loc.x + 1, loc.y - 1}, layout, brush);
        }
        this->pRenderTarget->DrawTextLayout({loc.x, loc.y}, layout, this->GetColorBrush(color));
        return tsize;
    }
    D2D1_SIZE_F DrawStringCentVertical(std::string str, float x, float y, D2D1_COLOR_F color, IDWriteTextLayout **_recodeLayout = nullptr, D2D1_COLOR_F back = {0.0f, 0.0f, 0.0f, 0.0f}, D2dFont *font = nullptr)
    {
        D2D1_SIZE_F tsize = {0, 0};
        AutoFree<wchar_t> tmp = Convert::A2W(str);
        IDWriteTextLayout *textLayout = CreateStringLayout(str, font ? font : this->DefaultFontObject);
        if (textLayout)
        {
            DWRITE_TEXT_METRICS metrics;
            auto hr = textLayout->GetMetrics(&metrics);
            if (SUCCEEDED(hr))
            {
                tsize = D2D1::Size((float)ceil(metrics.widthIncludingTrailingWhitespace), (float)ceil(metrics.height));
                D2D1_POINT_2F loc = {x, y - (tsize.height / 2.0f)};
                if (back.a > 0.0f)
                {
                    auto brush = this->GetColorBrush(back);
                    this->pRenderTarget->DrawTextLayout({loc.x - 1, loc.y - 1}, textLayout, brush);
                    this->pRenderTarget->DrawTextLayout({loc.x + 1, loc.y + 1}, textLayout, brush);
                    this->pRenderTarget->DrawTextLayout({loc.x - 1, loc.y + 1}, textLayout, brush);
                    this->pRenderTarget->DrawTextLayout({loc.x + 1, loc.y - 1}, textLayout, brush);
                }
                this->pRenderTarget->DrawTextLayout(
                    loc,
                    textLayout,
                    this->GetColorBrush(color));
            }
            if (_recodeLayout)
                *_recodeLayout = textLayout;
            else
                textLayout->Release();
        }
        return tsize;
    }
    D2D1_SIZE_F DrawStringCentVertical(std::wstring str, float x, float y, D2D1_COLOR_F color, IDWriteTextLayout **_recodeLayout = nullptr, D2D1_COLOR_F back = {0.0f, 0.0f, 0.0f, 0.0f}, D2dFont *font = nullptr)
    {
        D2D1_SIZE_F tsize = {0, 0};
        IDWriteTextLayout *textLayout = CreateStringLayout(str, font ? font : this->DefaultFontObject);
        if (textLayout)
        {
            DWRITE_TEXT_METRICS metrics;
            auto hr = textLayout->GetMetrics(&metrics);
            if (SUCCEEDED(hr))
            {
                tsize = D2D1::Size((float)ceil(metrics.widthIncludingTrailingWhitespace), (float)ceil(metrics.height));
                D2D1_POINT_2F loc = {x, y - (tsize.height / 2.0f)};
                if (back.a > 0.0f)
                {
                    auto brush = this->GetColorBrush(back);
                    this->pRenderTarget->DrawTextLayout({loc.x - 1, loc.y - 1}, textLayout, brush);
                    this->pRenderTarget->DrawTextLayout({loc.x + 1, loc.y + 1}, textLayout, brush);
                    this->pRenderTarget->DrawTextLayout({loc.x - 1, loc.y + 1}, textLayout, brush);
                    this->pRenderTarget->DrawTextLayout({loc.x + 1, loc.y - 1}, textLayout, brush);
                }
                this->pRenderTarget->DrawTextLayout(loc, textLayout, this->GetColorBrush(color));
            }
            if (_recodeLayout)
                *_recodeLayout = textLayout;
            else
                textLayout->Release();
        }
        return tsize;
    }
    void DrawStringLayout(std::string str, float x, float y, D2D1_COLOR_F color, D2D1_COLOR_F back = {0.0f, 0.0f, 0.0f, 0.0f}, D2dFont *font = nullptr)
    {
        AutoFree<wchar_t> tmp = Convert::A2W(str);
        IDWriteTextLayout *textLayout = CreateStringLayout(str, font ? font : this->DefaultFontObject);
        if (textLayout)
        {
            if (back.a > 0.0f)
            {
                auto brush = this->GetColorBrush(back);
                this->pRenderTarget->DrawTextLayout({x - 1, y - 1}, textLayout, brush);
                this->pRenderTarget->DrawTextLayout({x + 1, y + 1}, textLayout, brush);
                this->pRenderTarget->DrawTextLayout({x + 1, y - 1}, textLayout, brush);
                this->pRenderTarget->DrawTextLayout({x - 1, y + 1}, textLayout, brush);
            }
            this->pRenderTarget->DrawTextLayout({x, y}, textLayout, this->GetColorBrush(color));
            textLayout->Release();
        }
    }
    void DrawStringLayout(std::wstring str, float x, float y, D2D1_COLOR_F color, D2D1_COLOR_F back = {0.0f, 0.0f, 0.0f, 0.0f}, D2dFont *font = nullptr)
    {
        IDWriteTextLayout *textLayout = CreateStringLayout(str, font ? font : this->DefaultFontObject);
        if (textLayout)
        {
            if (back.a > 0.0f)
            {
                auto brush = this->GetColorBrush(back);
                this->GetColorBrush(back);
                this->pRenderTarget->DrawTextLayout({x - 1, y - 1}, textLayout, brush);
                this->pRenderTarget->DrawTextLayout({x + 1, y + 1}, textLayout, brush);
                this->pRenderTarget->DrawTextLayout({x + 1, y - 1}, textLayout, brush);
                this->pRenderTarget->DrawTextLayout({x - 1, y + 1}, textLayout, brush);
            }
            this->pRenderTarget->DrawTextLayout({x, y}, textLayout, this->GetColorBrush(color));
            textLayout->Release();
        }
    }
    void DrawStringLayout(std::wstring str, float x, float y, float w, float h, D2D1_COLOR_F color, D2D1_COLOR_F back = {0.0f, 0.0f, 0.0f, 0.0f}, D2dFont *font = nullptr)
    {
        IDWriteTextLayout *textLayout = CreateStringLayout(str, w, h, font ? font : this->DefaultFontObject);
        if (textLayout)
        {
            if (back.a > 0.0f)
            {
                auto brush = this->GetColorBrush(back);
                this->GetColorBrush(back);
                this->pRenderTarget->DrawTextLayout({x - 1, y - 1}, textLayout, brush);
                this->pRenderTarget->DrawTextLayout({x + 1, y + 1}, textLayout, brush);
                this->pRenderTarget->DrawTextLayout({x + 1, y - 1}, textLayout, brush);
                this->pRenderTarget->DrawTextLayout({x - 1, y + 1}, textLayout, brush);
            }
            this->pRenderTarget->DrawTextLayout({x, y}, textLayout, this->GetColorBrush(color));
            textLayout->Release();
        }
    }
    void DrawStringLayout(
        std::wstring str,
        float x, float y,
        D2D1_COLOR_F color,
        DWRITE_TEXT_RANGE subRange,
        D2D1_COLOR_F fontBack = {0.0f, 0.0f, 0.0f, 0.0f}, D2dFont *font = nullptr)
    {
        IDWriteTextLayout *textLayout = CreateStringLayout(str, font ? font : this->DefaultFontObject);
        if (textLayout)
        {
            textLayout->SetDrawingEffect(this->GetColorBrush(fontBack), subRange);
            this->pRenderTarget->DrawTextLayout({x, y}, textLayout, this->GetColorBrush(color));
            textLayout->Release();
        }
    }
    void DrawStringLayout(
        std::wstring str,
        float x, float y,
        float w, float h,
        D2D1_COLOR_F color,
        DWRITE_TEXT_RANGE subRange,
        D2D1_COLOR_F fontBack = {0.0f, 0.0f, 0.0f, 0.0f}, D2dFont *font = nullptr)
    {
        IDWriteTextLayout *textLayout = CreateStringLayout(str, w, h, font ? font : this->DefaultFontObject);
        if (textLayout)
        {
            textLayout->SetDrawingEffect(this->GetColorBrush(fontBack), subRange);
            this->pRenderTarget->DrawTextLayout({x, y}, textLayout, this->GetColorBrush(color));
            textLayout->Release();
        }
    }
    void DrawStringLayout(
        std::wstring str,
        float x, float y,
        float w, float h,
        ID2D1Brush *brush,
        DWRITE_TEXT_RANGE subRange,
        D2D1_COLOR_F fontBack = {0.0f, 0.0f, 0.0f, 0.0f}, D2dFont *font = nullptr)
    {
        IDWriteTextLayout *textLayout = CreateStringLayout(str, w, h, font ? font : this->DefaultFontObject);
        if (textLayout)
        {
            textLayout->SetDrawingEffect(this->GetColorBrush(fontBack), subRange);
            this->pRenderTarget->DrawTextLayout({x, y}, textLayout, brush);
            textLayout->Release();
        }
    }
    void DrawStringLayout(
        std::wstring str,
        float x, float y,
        float w, float h,
        D2D1_COLOR_F color,
        D2dFont *font = nullptr)
    {
        IDWriteTextLayout *textLayout = CreateStringLayout(str, w, h, font ? font : this->DefaultFontObject);
        if (textLayout)
        {
            this->pRenderTarget->DrawTextLayout({x, y}, textLayout, this->GetColorBrush(color));
            textLayout->Release();
        }
    }
    void DrawStringLayout(
        std::wstring str,
        float x, float y,
        float w, float h,
        ID2D1Brush *brush,
        D2dFont *font = nullptr)
    {
        IDWriteTextLayout *textLayout = CreateStringLayout(str, w, h, font ? font : this->DefaultFontObject);
        if (textLayout)
        {
            this->pRenderTarget->DrawTextLayout({x, y}, textLayout, brush);
            textLayout->Release();
        }
    }
    void FillTriangle(D2D1_TRIANGLE triangle, D2D1_COLOR_F color)
    {
        ID2D1PathGeometry *geo = nullptr;
        if (SUCCEEDED(_D2DFactory->CreatePathGeometry(&geo)))
        {
            ID2D1GeometrySink *tmp = NULL;
            if (SUCCEEDED(geo->Open(&tmp)))
            {
                tmp->BeginFigure(triangle.point1, D2D1_FIGURE_BEGIN_FILLED);
                tmp->AddLine(triangle.point2);
                tmp->AddLine(triangle.point3);
                tmp->AddLine(triangle.point1);
                tmp->EndFigure(D2D1_FIGURE_END::D2D1_FIGURE_END_CLOSED);
                tmp->Close();
                this->pRenderTarget->FillGeometry(geo, this->GetColorBrush(color));
                tmp->Release();
            }
            geo->Release();
        }
    }
    void DrawTriangle(D2D1_TRIANGLE triangle, D2D1_COLOR_F color, float width)
    {
        ID2D1PathGeometry *geo = nullptr;
        if (SUCCEEDED(_D2DFactory->CreatePathGeometry(&geo)))
        {
            ID2D1GeometrySink *tmp = NULL;
            if (SUCCEEDED(geo->Open(&tmp)))
            {
                tmp->BeginFigure(triangle.point1, D2D1_FIGURE_BEGIN_FILLED);
                tmp->AddLine(triangle.point2);
                tmp->AddLine(triangle.point3);
                tmp->AddLine(triangle.point1);
                tmp->EndFigure(D2D1_FIGURE_END::D2D1_FIGURE_END_CLOSED);
                tmp->Close();
                this->pRenderTarget->DrawGeometry(geo, this->GetColorBrush(color), width);
                tmp->Release();
            }
            geo->Release();
        }
    }
    void FillPolygon(std::initializer_list<D2D1_POINT_2F> points, D2D1_COLOR_F color)
    {
        ID2D1PathGeometry *geo = nullptr;
        if (SUCCEEDED(_D2DFactory->CreatePathGeometry(&geo)))
        {
            ID2D1GeometrySink *tmp = NULL;
            if (SUCCEEDED(geo->Open(&tmp)))
            {
                if (points.size() > 2)
                {
                    tmp->BeginFigure(points.begin()[0], D2D1_FIGURE_BEGIN_FILLED);
                    for (int i = 1; i < points.size(); i++)
                    {

                        tmp->AddLine(points.begin()[i]);
                    }
                    tmp->EndFigure(D2D1_FIGURE_END::D2D1_FIGURE_END_CLOSED);
                    tmp->Close();
                    this->pRenderTarget->FillGeometry(geo, this->GetColorBrush(color));
                    tmp->Release();
                }
            }
            geo->Release();
        }
    }
    void DrawPolygon(std::initializer_list<D2D1_POINT_2F> points, D2D1_COLOR_F color, float width)
    {
        ID2D1PathGeometry *geo = nullptr;
        if (SUCCEEDED(_D2DFactory->CreatePathGeometry(&geo)))
        {
            ID2D1GeometrySink *tmp = NULL;
            if (SUCCEEDED(geo->Open(&tmp)))
            {
                if (points.size() > 2)
                {
                    tmp->BeginFigure(points.begin()[0], D2D1_FIGURE_BEGIN_FILLED);
                    for (int i = 1; i < points.size(); i++)
                    {
                        tmp->AddLine(points.begin()[i]);
                    }
                    tmp->EndFigure(D2D1_FIGURE_END::D2D1_FIGURE_END_CLOSED);
                    tmp->Close();
                    this->pRenderTarget->DrawGeometry(geo, this->GetColorBrush(color), width);
                    tmp->Release();
                }
            }
            geo->Release();
        }
    }
    void DrawArc(D2D1_POINT_2F center, float size, float sa, float ea, D2D1_COLOR_F color, float width)
    {
        const auto __AngleToPoint = [](D2D1_POINT_2F Cent, float Angle, float Len)
        {
            if (Len <= 0)
                return Cent;
            return D2D1_POINT_2F{(Cent.x + (sin(Angle * 3.1415926535897931F / 180.0f) * Len)), (Cent.y - (cos(Angle * 3.1415926535897931F / 180.0f) * Len))};
        };
        ID2D1PathGeometry *geo = nullptr;
        if (SUCCEEDED(_D2DFactory->CreatePathGeometry(&geo)))
        {
            float ts = sa;
            float te = ea;
            if (te < ts)
                te += 360.0f;
            D2D1_ARC_SIZE sweep = (te - ts < 180.0f) ? D2D1_ARC_SIZE_SMALL : D2D1_ARC_SIZE_LARGE;
            ID2D1GeometrySink *pSink = NULL;
            if (SUCCEEDED(geo->Open(&pSink)))
            {
                D2D1_SWEEP_DIRECTION sw;
                auto start = __AngleToPoint(center, sa, size);
                auto end = __AngleToPoint(center, ea, size);
                pSink->BeginFigure(start, D2D1_FIGURE_BEGIN_FILLED);
                pSink->AddArc(
                    D2D1::ArcSegment(
                        end,
                        D2D1::SizeF(size, size),
                        0.0f,
                        D2D1_SWEEP_DIRECTION_CLOCKWISE,
                        sweep));
                pSink->EndFigure(D2D1_FIGURE_END::D2D1_FIGURE_END_OPEN);
                pSink->Close();
                this->pRenderTarget->DrawGeometry(geo, this->GetColorBrush(color), width);
                pSink->Release();
            }
            geo->Release();
        }
    }
    void DrawArcCounter(D2D1_POINT_2F center, float size, float sa, float ea, D2D1_COLOR_F color, float width)
    {
        const auto __AngleToPoint = [](D2D1_POINT_2F Cent, float Angle, float Len)
        {
            if (Len <= 0)
                return Cent;
            return D2D1_POINT_2F{(Cent.x + (sin(Angle * 3.1415926535897931F / 180.0f) * Len)), (Cent.y - (cos(Angle * 3.1415926535897931F / 180.0f) * Len))};
        };
        ID2D1PathGeometry *geo = nullptr;
        if (SUCCEEDED(_D2DFactory->CreatePathGeometry(&geo)))
        {
            float ts = sa;
            float te = ea;
            if (te < ts)
                te += 360.0f;
            D2D1_ARC_SIZE sweep = (te - ts < 180.0f) ? D2D1_ARC_SIZE_SMALL : D2D1_ARC_SIZE_LARGE;
            ID2D1GeometrySink *pSink = NULL;
            if (SUCCEEDED(geo->Open(&pSink)))
            {
                D2D1_SWEEP_DIRECTION sw;
                auto start = __AngleToPoint(center, sa, size);
                auto end = __AngleToPoint(center, ea, size);
                pSink->BeginFigure(start, D2D1_FIGURE_BEGIN_FILLED);
                pSink->AddArc(
                    D2D1::ArcSegment(
                        end,
                        D2D1::SizeF(size, size),
                        0.0f,
                        D2D1_SWEEP_DIRECTION_COUNTER_CLOCKWISE,
                        sweep));
                pSink->EndFigure(D2D1_FIGURE_END::D2D1_FIGURE_END_OPEN);
                pSink->Close();
                this->pRenderTarget->DrawGeometry(geo, this->GetColorBrush(color), width);
                pSink->Release();
            }
            geo->Release();
        }
    }
    D2D1_SIZE_F GetTextSize(std::wstring s, D2dFont *font = nullptr)
    {
        return (font ? font : this->DefaultFontObject)->GetTextSize(s);
    }
    D2D1_SIZE_F GetTextSize(wchar_t c, D2dFont *font = nullptr)
    {
        return (font ? font : this->DefaultFontObject)->GetTextSize(c);
    }
    // void PushDrawRect(float left, float top, float width, float height)
    //{
    //     ID2D1Layer* pLayer = NULL;
    //     this->pRenderTarget->PushLayer(
    //         D2D1::LayerParameters({
    //             left,
    //             top,
    //             left + width,
    //             top + height
    //             }),
    //         pLayer
    //     );
    // }
    // void PushDrawRect(RECT rec)
    //{
    //     ID2D1Layer* pLayer = NULL;
    //     this->pRenderTarget->PushLayer(
    //         D2D1::LayerParameters({
    //             (float)rec.left,
    //             (float)rec.top,
    //             (float)rec.right,
    //             (float)rec.bottom
    //             }),
    //         pLayer
    //     );
    // }
    // void PushDrawRect(D2D1_RECT_F rec)
    //{
    //     ID2D1Layer* pLayer = NULL;
    //     this->pRenderTarget->PushLayer(
    //         D2D1::LayerParameters({
    //             (float)rec.left,
    //             (float)rec.top,
    //             (float)rec.right,
    //             (float)rec.bottom
    //             }),
    //         pLayer
    //     );
    // }
    // void PushDrawRect(D2D1_RECT_U rec)
    //{
    //     ID2D1Layer* pLayer = NULL;
    //     this->pRenderTarget->PushLayer(
    //         D2D1::LayerParameters({
    //             (float)rec.left,
    //             (float)rec.top,
    //             (float)rec.right,
    //             (float)rec.bottom
    //             }),
    //         pLayer
    //     );
    // }
    // void PopDrawRect()
    //{
    //     this->pRenderTarget->PopLayer();
    // }

    void PushDrawRect(float left, float top, float width, float height)
    {
        this->pRenderTarget->PushAxisAlignedClip(
            {left,
             top,
             left + width,
             top + height},
            D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
    }
    void PopDrawRect()
    {
        this->pRenderTarget->PopAxisAlignedClip();
    }
    void SetAntialiasMode(D2D1_ANTIALIAS_MODE antialiasMode)
    {
        pRenderTarget->SetAntialiasMode(antialiasMode);
    }
    void SetTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE antialiasMode)
    {
        pRenderTarget->SetTextAntialiasMode(antialiasMode);
    }
    IUnknown *ToBitmap()
    {
        if (_Target_Type == __bitmap)
        {
            ID2D1Bitmap *bmp = NULL;
            ((ID2D1BitmapRenderTarget *)pRenderTarget)->GetBitmap(&bmp);
            return bmp;
        }
        else if (_Target_Type == __wic)
        {
            return this->pWICBitmap;
        }
        else
        {
            IWICBitmap *_WICBitmap = NULL;
            auto size = pRenderTarget->GetSize();
            _ImageFactory->CreateBitmap((UINT)size.width, (UINT)size.height, GUID_WICPixelFormat32bppBGR, WICBitmapCacheOnLoad, &_WICBitmap);
            auto bmp = this->CreateBitmap(_WICBitmap);
            D2D1_POINT_2U p = D2D1_POINT_2U{(UINT)size.width, (UINT)size.height};
            D2D1_RECT_U r = {0, 0, (UINT)size.width, (UINT)size.height};
            auto st = bmp->CopyFromRenderTarget(&p, pRenderTarget, &r);
            _WICBitmap->Release();
            return bmp;
        }
    }
    ID2D1Bitmap *CreateBitmap(IWICBitmap *wb)
    {
        ID2D1Bitmap *bmp;
        auto hr = this->pRenderTarget->CreateBitmapFromWicBitmap(wb, &bmp);
        return bmp;
    }
    ID2D1Bitmap *CreateBitmap(const char *path)
    {
        ID2D1Bitmap *bmp = nullptr;
        IWICBitmapDecoder *bitmapdecoder = NULL;
        AutoFree<wchar_t> tmp = Convert::A2W(path);
        _ImageFactory->CreateDecoderFromFilename(tmp, NULL, GENERIC_READ, WICDecodeMetadataCacheOnDemand, &bitmapdecoder); //
        if (bitmapdecoder)
        {
            IWICBitmapFrameDecode *pframe = NULL;
            bitmapdecoder->GetFrame(0, &pframe);
            IWICFormatConverter *fmtcovter = NULL;
            _ImageFactory->CreateFormatConverter(&fmtcovter);
            fmtcovter->Initialize(pframe, GUID_WICPixelFormat32bppPBGRA, WICBitmapDitherTypeNone, NULL, 0.0f, WICBitmapPaletteTypeCustom);
            this->pRenderTarget->CreateBitmapFromWicBitmap(fmtcovter, NULL, &bmp);
            pframe->Release();
            fmtcovter->Release();
            bitmapdecoder->Release();
        }
        return bmp;
    }
    ID2D1Bitmap *CreateBitmap(const wchar_t *path)
    {
        ID2D1Bitmap *bmp = nullptr;
        IWICBitmapDecoder *bitmapdecoder = NULL;
        _ImageFactory->CreateDecoderFromFilename(path, NULL, GENERIC_READ, WICDecodeMetadataCacheOnDemand, &bitmapdecoder); //
        if (bitmapdecoder)
        {
            IWICBitmapFrameDecode *pframe = NULL;
            bitmapdecoder->GetFrame(0, &pframe);
            IWICFormatConverter *fmtcovter = NULL;
            _ImageFactory->CreateFormatConverter(&fmtcovter);
            fmtcovter->Initialize(pframe, GUID_WICPixelFormat32bppPBGRA, WICBitmapDitherTypeNone, NULL, 0.0f, WICBitmapPaletteTypeCustom);
            this->pRenderTarget->CreateBitmapFromWicBitmap(fmtcovter, NULL, &bmp);
            pframe->Release();
            fmtcovter->Release();
            bitmapdecoder->Release();
        }
        return bmp;
    }
    ID2D1Bitmap *CreateBitmap(unsigned char *data, int size)
    {
        ID2D1Bitmap *bmp = nullptr;
        IWICBitmapDecoder *bitmapdecoder = NULL;
        IWICStream *pStream;
        auto errmsg = _ImageFactory->CreateStream(&pStream);
        if (!SUCCEEDED(errmsg))
        {
            return nullptr;
        }
        errmsg = pStream->InitializeFromMemory(data, size);
        if (!SUCCEEDED(errmsg))
        {
            return nullptr;
        }
        errmsg = _ImageFactory->CreateDecoderFromStream(pStream, NULL, WICDecodeMetadataCacheOnDemand, &bitmapdecoder);
        if (!SUCCEEDED(errmsg))
        {
            return nullptr;
        }
        if (bitmapdecoder)
        {
            IWICBitmapFrameDecode *pframe = NULL;
            bitmapdecoder->GetFrame(0, &pframe);
            IWICFormatConverter *fmtcovter = NULL;
            _ImageFactory->CreateFormatConverter(&fmtcovter);
            fmtcovter->Initialize(pframe, GUID_WICPixelFormat32bppPBGRA, WICBitmapDitherTypeNone, NULL, 0.0f, WICBitmapPaletteTypeCustom);
            this->pRenderTarget->CreateBitmapFromWicBitmap(fmtcovter, NULL, &bmp);
            pframe->Release();
            fmtcovter->Release();
            bitmapdecoder->Release();
        }
        return bmp;
    }
    ID2D1Bitmap *CreateBitmap(HBITMAP hb)
    {
        IWICBitmap *wb = nullptr;
        ID2D1Bitmap *bmp;
        _ImageFactory->CreateBitmapFromHBITMAP(hb, 0, WICBitmapUsePremultipliedAlpha, &wb);
        auto hr = this->pRenderTarget->CreateBitmapFromWicBitmap(wb, &bmp);
        wb->Release();
        return bmp;
    }
    ID2D1Bitmap *CreateBitmap(HICON hb)
    {
        IWICBitmap *wb = nullptr;
        ID2D1Bitmap *bmp = nullptr;
        _ImageFactory->CreateBitmapFromHICON(hb, &wb);
        this->pRenderTarget->CreateBitmapFromWicBitmap(wb, &bmp);
        wb->Release();
        return bmp;
    }
    ID2D1Bitmap *CreateBitmap(int width, int height)
    {
        IWICBitmap *wb = nullptr;
        ID2D1Bitmap *bmp;
        _ImageFactory->CreateBitmap(width, height, GUID_WICPixelFormat32bppPBGRA, WICBitmapCacheOnDemand, &wb);
        auto hr = this->pRenderTarget->CreateBitmapFromWicBitmap(wb, &bmp);
        wb->Release();
        return bmp;
    }
    static IWICBitmap *CreateWICBitmap(ID2D1Bitmap *bmp)
    {
        IWICBitmap *wb = nullptr;
        _ImageFactory->CreateBitmap(bmp->GetSize().width, bmp->GetSize().height, GUID_WICPixelFormat32bppPBGRA, WICBitmapCacheOnLoad, &wb);
        return wb;
    }
    static IWICBitmap *CreateWICBitmap(const char *path)
    {
        IWICBitmap *wb = NULL;
        IWICBitmapDecoder *bitmapdecoder = NULL;
        AutoFree<wchar_t> tmp = Convert::A2W(path);
        _ImageFactory->CreateDecoderFromFilename(tmp, NULL, GENERIC_READ, WICDecodeMetadataCacheOnDemand, &bitmapdecoder);
        if (bitmapdecoder)
        {
            IWICBitmapFrameDecode *pframe = NULL;
            bitmapdecoder->GetFrame(0, &pframe);
            IWICFormatConverter *fmtcovter = NULL;
            _ImageFactory->CreateFormatConverter(&fmtcovter);
            fmtcovter->Initialize(pframe, GUID_WICPixelFormat32bppPBGRA, WICBitmapDitherTypeNone, NULL, 0.0f, WICBitmapPaletteTypeCustom);
            pframe->Release();
            bitmapdecoder->Release();
            return (IWICBitmap *)fmtcovter;
        }
        return wb;
    }
    static IWICBitmap *CreateWICBitmap(unsigned char *data, int size)
    {
        ID2D1Bitmap *bmp = nullptr;
        IWICBitmapDecoder *bitmapdecoder = NULL;
        IWICStream *pStream;
        auto errmsg = _ImageFactory->CreateStream(&pStream);
        if (!SUCCEEDED(errmsg))
        {
            return nullptr;
        }
        errmsg = pStream->InitializeFromMemory(data, size);
        if (!SUCCEEDED(errmsg))
        {
            return nullptr;
        }
        errmsg = _ImageFactory->CreateDecoderFromStream(pStream, NULL, WICDecodeMetadataCacheOnDemand, &bitmapdecoder);
        if (!SUCCEEDED(errmsg))
        {
            return nullptr;
        }
        if (bitmapdecoder)
        {
            IWICBitmapFrameDecode *pframe = NULL;
            bitmapdecoder->GetFrame(0, &pframe);
            IWICFormatConverter *fmtcovter = NULL;
            _ImageFactory->CreateFormatConverter(&fmtcovter);
            fmtcovter->Initialize(pframe, GUID_WICPixelFormat32bppPBGRA, WICBitmapDitherTypeNone, NULL, 0.0f, WICBitmapPaletteTypeCustom);
            pframe->Release();
            bitmapdecoder->Release();
            return (IWICBitmap *)fmtcovter;
        }
        return NULL;
    }
    static IWICBitmap *CreateWICBitmap(HBITMAP hb)
    {
        IWICBitmap *wb = nullptr;
        _ImageFactory->CreateBitmapFromHBITMAP(hb, 0, WICBitmapUsePremultipliedAlpha, &wb);
        return wb;
    }
    static IWICBitmap *CreateWICBitmap(int width, int height)
    {
        IWICBitmap *wb = nullptr;
        _ImageFactory->CreateBitmap(width, height, GUID_WICPixelFormat32bppPBGRA, WICBitmapCacheOnDemand, &wb);
        return wb;
    }
    static IWICBitmap *CreateWICBitmap(HICON hb)
    {
        IWICBitmap *wb = nullptr;
        _ImageFactory->CreateBitmapFromHICON(hb, &wb);
        return wb;
    }
    static void SaveBitmap(IWICBitmap *bmp, const wchar_t *path)
    {
        UINT w, h;
        bmp->GetSize(&w, &h);
        IWICBitmapEncoder *pEncoder = NULL;
        IWICStream *pStream = NULL;
        IWICBitmapFrameEncode *pFrameEncode = NULL;
        WICPixelFormatGUID format = GUID_WICPixelFormat32bppPBGRA;
        _ImageFactory->CreateStream(&pStream);
        _ImageFactory->CreateEncoder(GUID_ContainerFormatPng, NULL, &pEncoder);
        pStream->InitializeFromFilename(path, GENERIC_WRITE);
        pEncoder->Initialize(pStream, WICBitmapEncoderNoCache);
        pEncoder->CreateNewFrame(&pFrameEncode, NULL);
        pFrameEncode->Initialize(NULL);
        pFrameEncode->SetSize(w, h);
        pFrameEncode->SetPixelFormat(&format);
        pFrameEncode->WriteSource(bmp, NULL);
        pFrameEncode->Commit();
        pEncoder->Commit();
        pFrameEncode->Release();
        pStream->Release();
        pEncoder->Release();
    }
    std::vector<ID2D1Bitmap *> CreateBitmapFromGif(const char *path)
    {
        std::vector<ID2D1Bitmap *> result = std::vector<ID2D1Bitmap *>();
        ID2D1Bitmap *bmp = nullptr;
        IWICBitmapDecoder *bitmapdecoder = NULL;
        AutoFree<wchar_t> tmp = Convert::A2W(path);
        _ImageFactory->CreateDecoderFromFilename(tmp, NULL, GENERIC_READ, WICDecodeMetadataCacheOnLoad, &bitmapdecoder);
        if (bitmapdecoder)
        {
            UINT count = 0;
            bitmapdecoder->GetFrameCount(&count);
            for (int i = 0; i < count; i++)
            {
                IWICBitmapFrameDecode *pframe = NULL;
                bitmapdecoder->GetFrame(i, &pframe);
                IWICFormatConverter *fmtcovter = NULL;
                _ImageFactory->CreateFormatConverter(&fmtcovter);
                fmtcovter->Initialize(pframe, GUID_WICPixelFormat32bppPBGRA, WICBitmapDitherTypeNone, NULL, 0.0f, WICBitmapPaletteTypeCustom);
                this->pRenderTarget->CreateBitmapFromWicBitmap(fmtcovter, NULL, &bmp);
                pframe->Release();
                fmtcovter->Release();
                result.push_back(bmp);
            }
            bitmapdecoder->Release();
        }
        return result;
    }
    std::vector<ID2D1Bitmap *> CreateBitmapFromGifBuffer(unsigned char *data, int size)
    {
        std::vector<ID2D1Bitmap *> result = std::vector<ID2D1Bitmap *>();
        ID2D1Bitmap *bmp = nullptr;
        IWICBitmapDecoder *bitmapdecoder = NULL;
        IWICStream *pStream;
        auto errmsg = _ImageFactory->CreateStream(&pStream);
        if (!SUCCEEDED(errmsg))
        {
            return result;
        }
        errmsg = pStream->InitializeFromMemory(data, size);
        if (!SUCCEEDED(errmsg))
        {
            return result;
        }
        errmsg = _ImageFactory->CreateDecoderFromStream(pStream, NULL, WICDecodeMetadataCacheOnDemand, &bitmapdecoder);
        if (!SUCCEEDED(errmsg))
        {
            return result;
        }
        if (bitmapdecoder)
        {
            UINT count = 0;
            bitmapdecoder->GetFrameCount(&count);

            for (int i = 0; i < count; i++)
            {
                IWICBitmapFrameDecode *pframe = NULL;
                bitmapdecoder->GetFrame(i, &pframe);
                IWICFormatConverter *fmtcovter = NULL;
                _ImageFactory->CreateFormatConverter(&fmtcovter);
                fmtcovter->Initialize(pframe, GUID_WICPixelFormat32bppPBGRA, WICBitmapDitherTypeNone, NULL, 0.0f, WICBitmapPaletteTypeCustom);
                this->pRenderTarget->CreateBitmapFromWicBitmap(fmtcovter, NULL, &bmp);
                pframe->Release();
                fmtcovter->Release();
                result.push_back(bmp);
            }
            bitmapdecoder->Release();
        }
        return result;
    }
    static ID2D1PathGeometry *CreateGeomtry()
    {
        ID2D1PathGeometry *geo = nullptr;
        HRESULT hr = _D2DFactory->CreatePathGeometry(&geo);
        if (SUCCEEDED(hr))
            return geo;
        else
            return nullptr;
    }
    static HBITMAP GetHBITMAPFromImageFile(const wchar_t *path)
    {
        HBITMAP hBitmap = (HBITMAP)LoadImageW(NULL, path, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
        return hBitmap;
    }
    static HBITMAP CopyFromScreen(int x, int y, int width, int height)
    {
        HDC hScreen = GetDC(NULL);
        HDC hDC = CreateCompatibleDC(hScreen);
        HBITMAP hBitmap = CreateCompatibleBitmap(hScreen, width, height);
        HGDIOBJ old_obj = SelectObject(hDC, hBitmap);
        BOOL bRet = BitBlt(hDC, x, y, width, height, hScreen, 0, 0, SRCCOPY);
        SelectObject(hDC, old_obj);
        DeleteDC(hDC);
        ReleaseDC(NULL, hScreen);
        return hBitmap;
    }
    static HBITMAP CopyFromWidnow(HWND handle, int x, int y, int width, int height)
    {
        HDC hScreen = GetDC(handle);
        HDC hDC = CreateCompatibleDC(hScreen);
        HBITMAP hBitmap = CreateCompatibleBitmap(hScreen, width, height);
        HGDIOBJ old_obj = SelectObject(hDC, hBitmap);
        BOOL bRet = BitBlt(hDC, x, y, width, height, hScreen, 0, 0, SRCCOPY);
        SelectObject(hDC, old_obj);
        DeleteDC(hDC);
        ReleaseDC(NULL, hScreen);
        return hBitmap;
    }
    static SIZE GetScreenSize(int index = 0)
    {
        std::vector<SIZE> sizes = std::vector<SIZE>();
        auto callback = [](HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData)
        {
            std::vector<SIZE> *tmp = (std::vector<SIZE> *)dwData;
            MONITORINFO info;
            info.cbSize = sizeof(info);
            if (GetMonitorInfoW(hMonitor, &info))
            {
                tmp->push_back({info.rcMonitor.right - info.rcMonitor.left, info.rcMonitor.bottom - info.rcMonitor.top});
            }
            return TRUE;
        };
        EnumDisplayMonitors(NULL, NULL, (MONITORENUMPROC)callback, (LPARAM)&sizes);
        if (sizes.size() > index)
        {
            return sizes[index];
        }
        return {GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN)};
    }
    ID2D1Bitmap *ToBitmapFromSvg(const char *data)
    {
        int len = strlen(data) + 1;
        AutoFree<char> svg_text(len);
        NSVGimage *image = nsvgParse(svg_text, "px", 96.0f);
        AutoFree<D2DGraphics> subg = this->CreateSubGraphics(image->width, image->height);
        NSVGshape *shape;
        NSVGpath *path;
        int i;
        subg->BeginRender();
        for (shape = image->shapes; shape != NULL; shape = shape->next)
        {
            auto geo = D2DGraphics::CreateGeomtry();
            if (geo)
            {
                ID2D1GeometrySink *skin = NULL;
                geo->Open(&skin);
                if (skin)
                {
                    for (path = shape->paths; path != NULL; path = path->next)
                    {
                        for (i = 0; i < path->npts - 1; i += 3)
                        {
                            float *p = &path->pts[i * 2];
                            if (i == 0)
                            {
                                skin->BeginFigure({p[0], p[1]}, D2D1_FIGURE_BEGIN_FILLED);
                            }
                            skin->AddBezier({{p[2], p[3]}, {p[4], p[5]}, {p[6], p[7]}});
                        }
                        skin->EndFigure(D2D1_FIGURE_END_CLOSED);
                    }
                }
                skin->Close();
            }
            const auto ic2fc = [](int c, float o)
            {
                D2D1_COLOR_F ret = {(float)GetRValue(c) / 255.0f, (float)GetGValue(c) / 255.0f, (float)GetBValue(c) / 255.0f, o};
                return ret;
            };
            if (shape->fill.gradient)
            {
            }

            D2D1_COLOR_F fill = ic2fc(shape->fill.color, shape->opacity);
            subg->FillGeometry(geo, fill);
            if (shape->stroke.color)
            {
                D2D1_COLOR_F stroke = ic2fc(shape->stroke.color, shape->opacity);
                subg->DrawGeometry(geo, Colors::Black, shape->strokeWidth);
            }
            geo->Release();
        }
        subg->EndRender();
        nsvgDelete(image);
        auto result = (ID2D1Bitmap *)subg->ToBitmap();
        return result;
    }
};